from selenium import webdriver
from time import sleep, time
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.chrome.options import Options
import json
import os
import requests
import re
from urllib.parse import urlparse
from datetime import datetime

# 全局静态变量：用于跟踪重定向文件和实施休息机制
REDIRECT_FILE_COUNT = 0  # 已创建重定向文件的计数器
REST_THRESHOLD = 2  # 休息前处理的重定向文件数量阈值
REST_DURATION = 10  # 休息持续时间（秒）
LAST_REST_TIME = 0  # 上次休息的时间戳

# 滚动相关的防封号变量
SCROLL_COUNT = 0  # 滚动次数计数器
SCROLL_REST_THRESHOLD = 2  # 滚动多少次后休息


def check_and_take_scroll_rest():
    """
    检查滚动次数是否需要休息以避免封号和封IP
    当滚动次数达到阈值时，休息指定时间
    """
    global SCROLL_COUNT, LAST_REST_TIME

    if SCROLL_COUNT >= SCROLL_REST_THRESHOLD:
        current_time = time()
        print(f"\n🛡️ === 滚动防封号休息机制触发 === 🛡️")
        print(f"📊 已滚动 {SCROLL_COUNT} 次，达到滚动休息阈值 ({SCROLL_REST_THRESHOLD})")
        print(f"⏰ 为了避免因频繁滚动导致封号和封IP，现在休息 {REST_DURATION} 秒 ({REST_DURATION // 60} 分钟)...")
        print(f"🔄 休息期间请勿关闭程序，系统将自动恢复滚动")
        print("-" * 50)

        # 显示倒计时
        if REST_DURATION >= 30:
            # 大于30秒时，每30秒显示一次进度
            for remaining in range(REST_DURATION, 0, -30):
                mins = remaining // 60
                secs = remaining % 60
                print(f"  ⏳ 滚动休息中... 剩余 {remaining} 秒 ({mins}分{secs}秒)")
                sleep(30)
        else:
            # 小于30秒时，每秒显示一次进度或直接等待
            if REST_DURATION <= 5:
                # 5秒以内直接等待
                print(f"  ⏳ 滚动休息 {REST_DURATION} 秒...")
                sleep(REST_DURATION)
            else:
                # 5秒以上每秒显示进度
                for remaining in range(REST_DURATION, 0, -1):
                    print(f"  ⏳ 滚动休息中... 剩余 {remaining} 秒")
                    sleep(1)

        print("  ✅ 滚动休息完毕，继续滚动处理...")
        print("🛡️ === 滚动休息结束 === 🛡️\n")

        # 重置滚动计数器和更新休息时间
        SCROLL_COUNT = 0
        LAST_REST_TIME = time()


def increment_scroll_count():
    """
    增加滚动次数计数并检查是否需要休息
    """
    global SCROLL_COUNT
    SCROLL_COUNT += 1
    print(f"  -> 【滚动防封号机制】滚动次数: {SCROLL_COUNT}/{SCROLL_REST_THRESHOLD}")

    # 检查是否需要休息
    check_and_take_scroll_rest()


def check_and_take_rest():
    """
    检查是否需要休息以避免封号和封IP
    当重定向文件数量达到阈值时，休息指定时间
    """
    global REDIRECT_FILE_COUNT, LAST_REST_TIME

    if REDIRECT_FILE_COUNT >= REST_THRESHOLD:
        current_time = time()
        print(f"\n🛡️ === 防封号休息机制触发 === 🛡️")
        print(f"📊 已处理 {REDIRECT_FILE_COUNT} 个重定向文件，达到休息阈值 ({REST_THRESHOLD})")
        print(f"⏰ 为了避免封号和封IP，现在休息 {REST_DURATION} 秒 ({REST_DURATION // 60} 分钟)...")
        print(f"🔄 休息期间请勿关闭程序，系统将自动恢复处理")
        print("-" * 50)

        # 显示倒计时
        if REST_DURATION >= 30:
            # 大于30秒时，每30秒显示一次进度
            for remaining in range(REST_DURATION, 0, -30):
                mins = remaining // 60
                secs = remaining % 60
                print(f"  ⏳ 休息中... 剩余 {remaining} 秒 ({mins}分{secs}秒)")
                sleep(30)
        else:
            # 小于30秒时，每秒显示一次进度或直接等待
            if REST_DURATION <= 5:
                # 5秒以内直接等待
                print(f"  ⏳ 休息 {REST_DURATION} 秒...")
                sleep(REST_DURATION)
            else:
                # 5秒以上每秒显示进度
                for remaining in range(REST_DURATION, 0, -1):
                    print(f"  ⏳ 休息中... 剩余 {remaining} 秒")
                    sleep(1)

        print("  ✅ 休息完毕，继续处理...")
        print("🛡️ === 休息结束 === 🛡️\n")

        # 重置计数器和更新休息时间
        REDIRECT_FILE_COUNT = 0
        LAST_REST_TIME = time()


def increment_redirect_count():
    """
    增加重定向文件计数并检查是否需要休息
    """
    global REDIRECT_FILE_COUNT
    REDIRECT_FILE_COUNT += 1
    print(f"  -> 【防封号机制】重定向文件计数: {REDIRECT_FILE_COUNT}/{REST_THRESHOLD}")

    # 检查是否需要休息
    check_and_take_rest()


def process_xiaohongshu_urls_click_images(url_list):
    """
    处理小红书URL列表，使用点击图片获取重定向地址的新策略
    
    参数:
        url_list (list): 小红书URL列表
        
    返回:
        dict: 处理结果
    """

    # 设置下载路径
    download_path = r"H:\download\tmp"
    chrome_history_path = r"H:\download\chrome\profile"

    # 设置 ChromeOptions
    chrome_options = Options()
    chrome_options.add_experimental_option("prefs", {
        "download.default_directory": download_path,
        "download.prompt_for_download": False,
        "download.directory_upgrade": True,
        "safebrowsing.enabled": True,
        "profile.default_content_settings.popups": 0
    })

    # 指定用户数据目录以保存登录状态
    chrome_options.add_argument(r"--user-data-dir=H:\download\userdata")
    chrome_options.add_argument("--disable-web-security")
    chrome_options.add_argument("--disable-features=VizDisplayCompositor")
    chrome_options.add_argument("--start-minimized")

    # 确保用户数据目录存在
    userdata_dir = r"H:\download\userdata"
    if not os.path.exists(userdata_dir):
        os.makedirs(userdata_dir)
        print(f"创建用户数据目录: {userdata_dir}")

    # 创建Chrome浏览器对象
    service = Service('D:\\chromedriver-win64\\chromedriver.exe')
    driver = webdriver.Chrome(service=service, options=chrome_options)
    driver.set_window_size(1600, 1000)

    print(f"Chrome用户数据目录: {userdata_dir}")
    print("如果登录成功，用户数据将保存到此目录，下次运行时会自动恢复登录状态")

    results = {
        'total_urls': len(url_list),
        'processed_urls': [],
        'login_required': False,
        'login_completed': False,
        'errors': [],
        'timestamp': datetime.now().isoformat()
    }

    try:
        # 处理第一个URL来检测登录状态
        if url_list:
            first_url = url_list[0]
            print(f"正在访问第一个URL检测登录状态: {first_url}")

            driver.get(first_url)
            sleep(3)

            # 检测是否需要登录
            login_status = check_xiaohongshu_login_status(driver)
            results['login_required'] = login_status['need_login']

            if login_status['need_login']:
                print("检测到需要登录，正在尝试点击登录按钮...")
                login_success = handle_xiaohongshu_login(driver)

                if login_success:
                    print("登录按钮已点击，请在浏览器中完成扫码登录...")
                    login_completed = wait_for_login_completion(driver)
                    results['login_completed'] = login_completed

                    if results['login_completed']:
                        print("检测到登录成功！开始处理URL列表...")
                    else:
                        print("登录超时或失败，请检查登录状态")
                        results['errors'].append("登录超时或失败")
                        return results
                else:
                    print("无法找到或点击登录按钮")
                    results['errors'].append("无法找到登录按钮")
                    return results
            else:
                print("检测到已登录状态，直接开始处理URL列表...")
                results['login_completed'] = True

            # 如果登录成功或无需登录，开始处理所有URL
            if results['login_completed'] or not results['login_required']:
                for i, url in enumerate(url_list):
                    try:
                        print(f"正在处理第 {i + 1}/{len(url_list)} 个URL: {url}")

                        # 访问URL
                        driver.get(url)
                        sleep(2)

                        # 使用新的点击图片策略处理单个URL
                        url_result = process_single_xiaohongshu_url_click_images(driver, url)

                        results['processed_urls'].append({
                            'url': url,
                            'index': i + 1,
                            'status': 'success',
                            'result': url_result,
                            'timestamp': datetime.now().isoformat()
                        })

                        print(f"URL {i + 1} 处理完成，提取到 {len(url_result.get('redirected_urls', []))} 个重定向URL，下载了 {len(url_result.get('downloaded_images', []))} 个图片")

                        # 立即保存单个URL的结果到独立文件
                        # 修改条件：只要有重定向URL或者下载了图片就保存，或者至少要保存一个文件
                        has_redirected_urls = url_result.get('redirected_urls') and len(url_result.get('redirected_urls', [])) > 0
                        has_downloaded_images = url_result.get('downloaded_images') and len(url_result.get('downloaded_images', [])) > 0
                        
                        # 即使没有内容，也要保存一个基本的JSON文件记录处理状态
                        should_save = (
                            url_result.get('status') == 'success' and 
                            (has_redirected_urls or has_downloaded_images)
                        ) or True  # 始终保存，保证每个URL都有记录
                        
                        if should_save:
                            print(f"\n=== 正在保存第 {i + 1}/{len(url_list)} 个URL的独立文件 ===")
                            print(f"     重定向URL: {len(url_result.get('redirected_urls', []))} 个")
                            print(f"     下载图片: {len(url_result.get('downloaded_images', []))} 个")
                            print(f"     点击链接: {url_result.get('total_images_clicked', 0)} 个")

                            # 保存重定向URL文件和拼接字符串文件
                            redirected_path, concat_path, url_count = save_single_url_result_click_images(
                                url_result, i + 1, len(url_list)
                            )

                            print(f"     ✓ 第 {i + 1} 个URL的文件保存完成")
                            print(f"     ✓ 重定向URL数量: {url_count}")
                            print(f"     ✓ 下载图片数量: {len(url_result.get('downloaded_images', []))}")
                            print(f"     ✓ JSON文件: {os.path.basename(redirected_path) if redirected_path else '保存失败'}")
                        else:
                            # 这个分支实际上不会达到，但保留作为备用
                            print(f"     - 第 {i + 1} 个URL未提取到有效内容且未下载图片，但仍保存基本信息")

                    except Exception as e:
                        error_msg = f"处理URL {i + 1} 时出错: {str(e)}"
                        print(error_msg)
                        results['errors'].append(error_msg)
                        results['processed_urls'].append({
                            'url': url,
                            'index': i + 1,
                            'status': 'error',
                            'error': str(e),
                            'timestamp': datetime.now().isoformat()
                        })

        return results, driver

    except Exception as e:
        error_msg = f"处理过程中出现严重错误: {str(e)}"
        print(error_msg)
        results['errors'].append(error_msg)
        return results, driver


def process_single_xiaohongshu_url_click_images(driver, url):
    """
    处理单个小红书URL - 使用点击图片获取重定向地址的策略
    
    Args:
        driver: WebDriver实例
        url: 要处理的URL
        
    Returns:
        dict: 处理结果
    """
    
    print(f"  -> 开始使用点击图片策略提取重定向URL: {url}")
    
    try:
        # 等待页面加载完成
        sleep(3)
        
        # 检查页面是否正确加载
        page_title = driver.title
        current_url = driver.current_url
        print(f"  -> 页面加载完成: {page_title}")
        print(f"  -> 当前URL: {current_url}")
        
        # 检查是否存在userPostedFeeds容器
        try:
            container = driver.find_element(By.CSS_SELECTOR, "#userPostedFeeds")
            print(f"  -> ✓ 找到userPostedFeeds容器")
        except:
            print(f"  -> ⚠️ 未找到userPostedFeeds容器，这可能影响链接提取")
        
        # 初始化URL收集器
        redirected_urls = []
        
        print("  -> 正在使用点击图片策略滚动和收集图片...")
        
        # 滚动并收集图片链接元素
        link_elements = collect_image_elements_with_scroll(driver)
        print(f"  -> 收集到 {len(link_elements)} 个图片链接元素")
        
        # 如果没有找到链接元素，输出调试信息
        if not link_elements:
            print(f"  -> ⚠️ 未找到任何可点击的图片链接")
            print(f"  -> 尝试查看页面源码以诊断问题...")
            
            # 输出页面的基本结构信息
            try:
                all_links = driver.find_elements(By.TAG_NAME, "a")
                print(f"  -> 页面总链接数量: {len(all_links)}")
                
                user_posted_feeds = driver.find_elements(By.CSS_SELECTOR, "#userPostedFeeds")
                print(f"  -> userPostedFeeds容器数量: {len(user_posted_feeds)}")
                
                cover_links = driver.find_elements(By.CSS_SELECTOR, "a[class*='cover']")
                print(f"  -> 包含cover的链接数量: {len(cover_links)}")
                
                # 显示前几个链接的信息
                if all_links[:3]:
                    print(f"  -> 前3个链接样例:")
                    for i, link in enumerate(all_links[:3]):
                        try:
                            href = link.get_attribute('href')
                            link_class = link.get_attribute('class')
                            print(f"    {i+1}. href: {href}")
                            print(f"       class: {link_class}")
                        except:
                            continue
                            
            except Exception as e:
                print(f"  -> 诊断信息获取失败: {e}")
        
        # 首先提取用户标题
        user_title = extract_user_title_from_page(driver)
        print(f"  -> 用户标题: {user_title}")
        
        # 点击每个图片链接获取重定向URL
        redirected_urls = []
        downloaded_images = []
        if link_elements:
            result = click_images_get_redirected_urls(driver, link_elements, user_title)
            redirected_urls = result.get('redirected_urls', [])
            downloaded_images = result.get('downloaded_images', [])
        else:
            print(f"  -> ⚠️ 没有找到可点击的图片链接，尝试其他方法...")
            # 如果没有找到链接元素，尝试直接在当前页面查找图片
            all_imgs = driver.find_elements(By.TAG_NAME, "img")
            if all_imgs:
                print(f"  -> 尝试强制下载当前页面的前5个图片...")
                downloaded_images = download_visible_images_forced(driver, all_imgs[:5], user_title, 1, 1)
        
        # 获取页面基本信息
        try:
            page_title = driver.title
        except Exception as e:
            page_title = "获取标题失败"
            print(f"  -> 获取页面标题时出错: {e}")
        
        result = {
            'url': url,
            'page_title': page_title,
            'user_title': user_title,
            'extraction_method': 'click_images',
            'total_images_clicked': len(link_elements),
            'total_redirected_urls': len(redirected_urls),
            'total_downloaded_images': len(downloaded_images),
            'redirected_urls': redirected_urls,
            'downloaded_images': downloaded_images,
            'status': 'success',
            'timestamp': datetime.now().isoformat()
        }
        
        print(f"  -> 点击图片策略完成！")
        print(f"  -> 找到链接元素: {len(link_elements)} 个")
        print(f"  -> 获取重定向URL: {len(redirected_urls)} 个")
        print(f"  -> 下载图片文件: {len(downloaded_images)} 个")
        return result
        
    except Exception as e:
        error_msg = f"点击图片提取URL出错: {str(e)}"
        print(f"  -> {error_msg}")
        return {
            'url': url,
            'status': 'error',
            'error': str(e),
            'redirected_urls': [],
            'timestamp': datetime.now().isoformat()
        }


def collect_image_elements_with_scroll(driver):
    """
    滚动页面并收集所有图片链接元素
    
    Args:
        driver: WebDriver实例
        
    Returns:
        list: 图片链接元素列表
    """
    
    print("  -> 开始滚动并收集图片链接元素...")
    
    # 先提取当前可见的图片链接
    all_links = set()
    
    # 滚动并收集图片链接
    max_scrolls = 15  # 最大滚动次数
    no_new_links_count = 0  # 连续无新图片链接的次数
    max_no_new = 3  # 连续3次无新图片链接就停止
    
    for scroll_round in range(max_scrolls):
        print(f"  -> 第 {scroll_round + 1} 轮滚动...")
        
        # 记录滚动前的链接数量
        before_count = len(all_links)
        
        # 提取当前视口的图片链接元素
        current_links = find_clickable_images(driver)
        
        # 添加到集合中（自动去重）
        for link in current_links:
            # 使用链接的href作为去重依据
            try:
                link_href = link.get_attribute('href')
                if link_href:
                    all_links.add((link_href, link))
            except:
                continue
        
        after_count = len(all_links)
        new_count = after_count - before_count
        
        print(f"  -> 本轮新增 {new_count} 个链接 (总计: {len(all_links)} 个)")
        
        if new_count > 0:
            no_new_links_count = 0  # 重置计数器
        else:
            no_new_links_count += 1
            print(f"  -> 无新链接 ({no_new_links_count}/{max_no_new})")
        
        # 检查停止条件
        if no_new_links_count >= max_no_new:
            print(f"  -> 连续{max_no_new}轮无新链接，提前停止滚动")
            break
        
        # 执行滚动操作
        scroll_success = perform_scroll_operation(driver, scroll_round)
        if not scroll_success:
            print(f"  -> 滚动失败，可能已到页面底部")
            break
        
        sleep(2)  # 等待内容加载
    
    # 提取链接元素（去除href，只保留元素）
    link_elements = [link_tuple[1] for link_tuple in all_links]
    
    print(f"  -> 滚动完成，共收集到 {len(link_elements)} 个唯一图片链接元素")
    return link_elements


def find_clickable_images(driver):
    """
    查找当前视口中可点击的图片链接元素（应该点击链接而不是图片本身）
    
    Args:
        driver: WebDriver实例
        
    Returns:
        list: 可点击的图片链接元素列表
    """
    
    clickable_links = []
    
    # 基于原始脚本的选择器策略，查找包含图片的链接元素
    # 按照从宽松到具体的顺序排列，提高找到链接的概率
    link_selectors = [
        # 最宽松的选择器放在前面
        "#userPostedFeeds a[href]",  # 任何有href的链接作为首选
        "#userPostedFeeds a",  # userPostedFeeds容器内的所有链接
        "a[href*='/explore/']",  # 全页面的explore链接
        "a[href*='/user/profile/']",  # 全页面的profile链接
        
        # 更具体的选择器
        "#userPostedFeeds a.cover",  # 任何包含cover class的链接
        "#userPostedFeeds a[class*='cover']",  # class包含cover的链接
        "#userPostedFeeds a[target='_self']",  # target为_self的链接
        "#userPostedFeeds a.cover[target='_self']",  # userPostedFeeds容器内的cover链接
        "#userPostedFeeds a[class*='cover'][target='_self']",  # class包含cover且target为_self
        "#userPostedFeeds a.cover.mask",  # class包含cover和mask
        "#userPostedFeeds a[class*='cover'][class*='mask']",  # class包含cover和mask
    ]
    
    print(f"    -> 开始查找包含图片的可点击链接...")
    print(f"    -> 当前页面URL: {driver.current_url}")
    print(f"    -> 页面标题: {driver.title}")
    
    # 首先检查userPostedFeeds容器是否存在
    try:
        container = driver.find_element(By.CSS_SELECTOR, "#userPostedFeeds")
        print(f"    -> ✓ 找到userPostedFeeds容器")
        container_links = container.find_elements(By.TAG_NAME, "a")
        print(f"    -> userPostedFeeds容器中总共有 {len(container_links)} 个链接")
    except:
        print(f"    -> ⚠️ 未找到userPostedFeeds容器，将搜索整个页面")
        all_page_links = driver.find_elements(By.TAG_NAME, "a")
        print(f"    -> 整个页面中总共有 {len(all_page_links)} 个链接")
    
    for selector_index, selector in enumerate(link_selectors):
        try:
            links = driver.find_elements(By.CSS_SELECTOR, selector)
            print(f"    -> 选择器 '{selector}' 找到 {len(links)} 个链接")
            
            for link in links:
                try:
                    # 检查链接是否可见且可点击
                    if not (link.is_displayed() and link.is_enabled()):
                        continue
                    
                    # 检查链接的href属性
                    href = link.get_attribute("href")
                    if not href:
                        continue
                    
                    # 过滤出相关的链接（放宽条件）
                    is_relevant_link = (
                        "/user/profile/" in href or 
                        "/explore/" in href or
                        "xiaohongshu.com" in href  # 包含小红书域名的链接
                    )
                    
                    if not is_relevant_link:
                        continue
                    
                    # 检查链接是否包含图片（放宽条件，不强制要求）
                    images_in_link = link.find_elements(By.TAG_NAME, "img")
                    # 注意：不再强制要求包含图片，因为有些链接可能使用背景图或CSS
                    
                    # 添加到可点击链接列表
                    clickable_links.append({
                        'element': link,
                        'href': href,
                        'selector': selector,
                        'images_count': len(images_in_link),
                        'class': link.get_attribute('class'),
                        'target': link.get_attribute('target')
                    })
                    
                except Exception as e:
                    continue
                    
            # 不再提早停止，继续尝试其他选择器以收集更多链接
            if clickable_links and len(clickable_links) >= 10:  # 只有当找到足够多链接时才停止
                print(f"    -> 使用选择器 '{selector}' 已找到足够链接 {len(clickable_links)} 个，停止搜索")
                break
            elif clickable_links:
                print(f"    -> 选择器 '{selector}' 找到 {len(clickable_links)} 个链接，继续尝试其他选择器...")
                
        except Exception as e:
            print(f"    -> 选择器 '{selector}' 执行失败: {e}")
            continue
    
    # 去重（基于href）
    unique_links = []
    seen_hrefs = set()
    
    for link_info in clickable_links:
        href = link_info['href']
        if href not in seen_hrefs:
            seen_hrefs.add(href)
            unique_links.append(link_info)
    
    print(f"    -> 找到 {len(unique_links)} 个唯一的可点击图片链接")
    
    # 返回元素列表（保持接口兼容）
    return [link_info['element'] for link_info in unique_links]


def click_images_get_redirected_urls(driver, link_elements, user_title="unknown"):
    """
    点击图片链接元素获取重定向URL并下载图片
    
    Args:
        driver: WebDriver实例
        link_elements: 图片链接元素列表
        user_title: 用户标题
        
    Returns:
        dict: 包含重定向URL和下载图片信息的结果
    """
    
    redirected_urls = []
    all_downloaded_images = []
    original_url = driver.current_url
    original_window = driver.current_window_handle
    
    print(f"  -> 开始点击 {len(link_elements)} 个图片链接获取重定向URL...")
    print(f"  -> 原始页面URL: {original_url}")
    
    for i, link_element in enumerate(link_elements):
        try:
            print(f"\n    -> 点击第 {i + 1}/{len(link_elements)} 个链接...")
            
            # 获取链接的详细信息用于调试
            try:
                href = link_element.get_attribute("href")
                link_class = link_element.get_attribute("class")
                target = link_element.get_attribute("target")
                print(f"      链接信息: href={href}")
                print(f"      class={link_class}")
                print(f"      target={target}")
            except Exception as e:
                print(f"      获取链接信息失败: {e}")
                continue
            
            # 滚动到链接可见位置
            try:
                driver.execute_script("arguments[0].scrollIntoView({block: 'center'});", link_element)
                sleep(1)
                print(f"      ✓ 滚动到链接位置")
            except Exception as e:
                print(f"      滚动失败: {e}")
            
            # 记录点击前的状态
            before_url = driver.current_url
            before_windows = len(driver.window_handles)
            
            # 点击链接
            success = click_link_element(driver, link_element)
            
            if success:
                print(f"      ✓ 链接点击成功")
                
                # 等待页面响应
                sleep(3)
                
                # 首先检查是否触发了二维码验证
                if check_for_qr_verification(driver):
                    print(f"      ⚠️ 触发二维码验证，等待用户扫码...")
                    verification_success = wait_for_qr_verification_completion(driver)
                    
                    if not verification_success:
                        print(f"      ❌ 二维码验证超时或失败，跳过此链接")
                        continue
                    
                    print(f"      ✅ 二维码验证完成，继续处理链接")
                    # 验证完成后再次等待页面加载
                    sleep(2)
                
                # 检查点击后的变化
                after_url = driver.current_url
                after_windows = len(driver.window_handles)
                
                print(f"      点击前URL: {before_url}")
                print(f"      点击后URL: {after_url}")
                print(f"      窗口数量变化: {before_windows} -> {after_windows}")
                
                if after_url != before_url:
                    # URL发生了变化，说明跳转到了新页面
                    print(f"      ✓ 检测到页面跳转: {after_url}")
                    redirected_urls.append(after_url)
                    
                    # 返回原页面
                    print(f"      <- 返回原页面...")
                    driver.back()
                    sleep(2)
                    
                elif after_windows > before_windows:
                    # 检查是否打开了新窗口
                    print(f"      检测到新窗口打开")
                    current_windows = driver.window_handles
                    
                    for window in current_windows:
                        if window != original_window:
                            print(f"      切换到新窗口...")
                            driver.switch_to.window(window)
                            new_url = driver.current_url
                            print(f"      ✓ 新窗口URL: {new_url}")
                            redirected_urls.append(new_url)
                            
                            # 关闭新窗口并切换回原窗口
                            driver.close()
                            driver.switch_to.window(original_window)
                            sleep(1)
                            break
                            
                else:
                    # 检查是否有dialog或overlay出现
                    print(f"      检查dialog或overlay...")
                    
                    # 等待dialog加载，尝试多次检测
                    dialog_result = None
                    max_dialog_attempts = 3
                    
                    for attempt in range(max_dialog_attempts):
                        print(f"      -> dialog检测尝试 {attempt + 1}/{max_dialog_attempts}")
                        sleep(2)  # 每次尝试前等待2秒
                        
                        dialog_result = check_for_dialog_or_overlay(driver, user_title, i + 1, len(link_elements))
                        
                        if dialog_result:
                            print(f"      ✓ 在第 {attempt + 1} 次尝试中找到dialog")
                            break
                        else:
                            print(f"      - 第 {attempt + 1} 次尝试未找到dialog")
                    
                    if dialog_result:
                        print(f"      ✓ 从dialog获取信息:")
                        if dialog_result.get('url'):
                            print(f"        URL: {dialog_result['url']}")
                            redirected_urls.append(dialog_result['url'])
                        
                        if dialog_result.get('downloaded_images'):
                            print(f"        下载图片: {len(dialog_result['downloaded_images'])} 个")
                            all_downloaded_images.extend(dialog_result['downloaded_images'])
                        
                        # 关闭dialog
                        print(f"      -> 准备关闭dialog...")
                        close_dialog_or_overlay(driver)
                        sleep(1)
                    else:
                        print(f"      - 多次尝试后仍未找到dialog")
                        
                        # 尝试直接检测页面变化，可能dialog已经加载但选择器不匹配
                        current_page_url = driver.current_url
                        if '/explore/' in current_page_url and current_page_url != before_url:
                            print(f"      -> 检测到页面URL包含explore: {current_page_url}")
                            redirected_urls.append(current_page_url)
                        
                        # 可能是SPA应用，检查DOM变化
                        check_dom_changes(driver)
                
            else:
                print(f"      - 点击链接失败")
                
        except Exception as e:
            print(f"      - 处理链接 {i + 1} 时出错: {e}")
            continue
            
        # 每点击几个链接后增加短暂休息，避免被检测为机器人行为
        if (i + 1) % 3 == 0:  # 减少频率，每3个链接休息一次
            print(f"    -> 已处理 {i + 1} 个链接，短暂休息...")
            sleep(3)
    
    print(f"\n  -> 链接点击完成，共获取到 {len(redirected_urls)} 个重定向URL")
    
    # 去重
    unique_urls = list(set(redirected_urls))
    print(f"  -> 去重后剩余 {len(unique_urls)} 个唯一URL")
    
    # 显示前几个URL样例
    if unique_urls:
        print(f"  -> URL样例:")
        for i, url in enumerate(unique_urls[:3]):
            print(f"    {i+1}. {url}")
    
    # 显示下载图片汇总
    if all_downloaded_images:
        print(f"  -> 图片下载汇总: 共下载 {len(all_downloaded_images)} 个图片文件")
        print(f"    前3个图片文件:")
        for i, img_path in enumerate(all_downloaded_images[:3]):
            print(f"    {i+1}. {os.path.basename(img_path)}")
    
    return {
        'redirected_urls': unique_urls,
        'downloaded_images': all_downloaded_images,
        'total_images': len(all_downloaded_images)
    }


def click_link_element(driver, link_element):
    """
    点击链接元素的通用方法
    
    Args:
        driver: WebDriver实例
        link_element: 链接元素
        
    Returns:
        bool: 是否成功点击
    """
    
    try:
        # 方法1: 直接点击
        print(f"        尝试直接点击...")
        link_element.click()
        print(f"        ✓ 直接点击成功")
        return True
        
    except Exception as click_error:
        print(f"        直接点击失败: {click_error}")
        
        try:
            # 方法2: JavaScript点击
            print(f"        尝试JavaScript点击...")
            driver.execute_script("arguments[0].click();", link_element)
            print(f"        ✓ JavaScript点击成功")
            return True
            
        except Exception as js_error:
            print(f"        JavaScript点击失败: {js_error}")
            
            try:
                # 方法3: ActionChains点击
                print(f"        尝试ActionChains点击...")
                ActionChains(driver).move_to_element(link_element).click().perform()
                print(f"        ✓ ActionChains点击成功")
                return True
                
            except Exception as action_error:
                print(f"        ActionChains点击失败: {action_error}")
                
                # 方法4: 尝试触发鼠标事件
                try:
                    print(f"        尝试触发鼠标事件...")
                    driver.execute_script("""
                        var element = arguments[0];
                        var event = new MouseEvent('click', {
                            view: window,
                            bubbles: true,
                            cancelable: true
                        });
                        element.dispatchEvent(event);
                    """, link_element)
                    print(f"        ✓ 鼠标事件触发成功")
                    return True
                except Exception as event_error:
                    print(f"        鼠标事件触发失败: {event_error}")
                    
                return False


def check_dom_changes(driver):
    """
    检查DOM变化，可能是SPA应用的页面更新
    
    Args:
        driver: WebDriver实例
    """
    try:
        # 检查是否有新的内容加载
        current_url = driver.current_url
        page_source_length = len(driver.page_source)
        
        print(f"        当前URL: {current_url}")
        print(f"        页面内容长度: {page_source_length}")
        
        # 检查是否有常见的加载指示器
        loading_selectors = [
            ".loading",
            "[class*='loading']",
            ".spinner",
            "[class*='spinner']"
        ]
        
        for selector in loading_selectors:
            try:
                loading_elements = driver.find_elements(By.CSS_SELECTOR, selector)
                if loading_elements:
                    print(f"        检测到加载指示器: {selector}")
                    break
            except:
                continue
        
    except Exception as e:
        print(f"        检查DOM变化失败: {e}")


def check_for_qr_verification(driver):
    """
    检查是否出现二维码验证页面
    检测文本："为了保护账号安全，请打开"，通常在标签：<div data-v-9f9809ef class="qrcode-desc">
    
    Args:
        driver: WebDriver实例
        
    Returns:
        bool: 是否检测到二维码验证
    """
    
    try:
        # 多种选择器策略来查找二维码描述文本
        qr_selectors = [
            "div.qrcode-desc[data-v-9f9809ef]",  # 完整匹配
            "div.qrcode-desc",  # 只匹配class
            "div[class*='qrcode-desc']",  # 包含qrcode-desc的class
            "[data-v-9f9809ef]",  # 匹配data属性
            "//div[contains(@class, 'qrcode-desc')]",  # XPath选择器
            "//div[contains(text(), '为了保护账号安全')]",  # 直接通过文本查找
            "//div[contains(text(), '请打开')]"  # 通过部分文本查找
        ]
        
        verification_keywords = [
            "为了保护账号安全，请打开",
            "为了保护账号安全",
            "请打开",
            "扫码验证",
            "二维码验证",
            "验证身份"
        ]
        
        print(f"    -> 检查是否出现二维码验证...")
        
        # 方法1: 通过选择器查找元素
        for selector in qr_selectors:
            try:
                if selector.startswith("//"):
                    elements = driver.find_elements(By.XPATH, selector)
                else:
                    elements = driver.find_elements(By.CSS_SELECTOR, selector)
                
                for element in elements:
                    if element.is_displayed():
                        element_text = element.text.strip()
                        print(f"    -> 找到可疑验证元素: '{element_text}' (选择器: {selector})")
                        
                        # 检查文本是否包含验证关键词
                        for keyword in verification_keywords:
                            if keyword in element_text:
                                print(f"    -> ⚠️ 检测到二维码验证: '{keyword}'")
                                return True
                                
            except Exception as e:
                continue
        
        # 方法2: 检查页面源码中是否包含关键文本
        try:
            page_source = driver.page_source
            for keyword in verification_keywords:
                if keyword in page_source:
                    print(f"    -> ⚠️ 页面源码中发现验证关键词: '{keyword}'")
                    return True
        except Exception as e:
            print(f"    -> 检查页面源码失败: {e}")
        
        # 方法3: 检查页面标题是否包含验证相关文本
        try:
            page_title = driver.title
            verification_title_keywords = ["验证", "安全", "扫码"]
            for keyword in verification_title_keywords:
                if keyword in page_title:
                    print(f"    -> ⚠️ 页面标题中发现验证关键词: '{keyword}' (标题: {page_title})")
                    return True
        except Exception as e:
            print(f"    -> 检查页面标题失败: {e}")
        
        print(f"    -> ✓ 未检测到二维码验证")
        return False
        
    except Exception as e:
        print(f"    -> 检测二维码验证时出错: {e}")
        return False


def wait_for_qr_verification_completion(driver, max_wait_time=300):
    """
    等待二维码验证完成
    
    Args:
        driver: WebDriver实例
        max_wait_time: 最大等待时间（秒），默认5分钟
        
    Returns:
        bool: 验证是否成功完成
    """
    
    print(f"\n🔐 === 二维码验证检测到 === 🔐")
    print(f"⚠️ 系统检测到需要进行二维码验证")
    print(f"📱 请在浏览器中扫码完成验证")
    print(f"⏰ 程序将等待最多 {max_wait_time} 秒 ({max_wait_time // 60} 分钟)")
    print(f"🔄 验证完成后程序将自动继续")
    print("-" * 60)
    
    start_time = time()
    check_interval = 5  # 每5秒检查一次
    
    while time() - start_time < max_wait_time:
        try:
            # 检查验证是否完成（验证元素消失）
            verification_exists = check_for_qr_verification(driver)
            
            if not verification_exists:
                print(f"✅ 检测到验证完成！")
                print(f"✅ 验证耗时: {int(time() - start_time)} 秒")
                print(f"🔄 程序继续执行...")
                print(f"🔐 === 验证完成 === 🔐\n")
                
                # 等待页面完全加载
                sleep(3)
                return True
            
            # 显示等待状态
            elapsed_time = int(time() - start_time)
            remaining_time = max_wait_time - elapsed_time
            
            print(f"  ⏳ 等待验证完成... (已等待 {elapsed_time}s，剩余 {remaining_time}s)")
            
            # 显示当前页面状态
            try:
                current_url = driver.current_url
                page_title = driver.title
                print(f"  📄 当前页面: {page_title}")
                print(f"  🔗 当前URL: {current_url}")
            except:
                pass
            
            sleep(check_interval)
            
        except Exception as e:
            print(f"  ❌ 检测验证状态时出错: {e}")
            sleep(check_interval)
            continue
    
    print(f"❌ 验证等待超时 ({max_wait_time}s)")
    print(f"🔐 === 验证超时 === 🔐\n")
    return False


def download_images_from_dialog(driver, user_title, url_index, total_urls):
    """
    从dialog中的swiper容器下载所有图片
    增强版本：添加更多调试信息和备用方案
    
    Args:
        driver: WebDriver实例
        user_title: 用户标题
        url_index: URL索引
        total_urls: 总URL数量
        
    Returns:
        list: 下载的图片文件路径列表
    """
    
    print(f"      -> 开始从dialog中下载图片...")
    print(f"      -> 当前页面URL: {driver.current_url}")
    
    # 首先尝试找到所有可能的图片，不局限于swiper
    all_dialog_images = []
    
    # 方法1：查找swiper容器
    swiper_selectors = [
        "div.swiper.note-slider",  # 基于class组合
        "div[class*='swiper'][class*='note-slider']",  # 包含两个class
        "div.swiper-initialized",  # swiper初始化标识  
        "div[data-v-2ae7b646][data-v-567c5164-s]",  # 基于data属性
        "div.swiper",  # 通用swiper选择器
        ".swiper-wrapper",  # swiper包装器
        "[class*='swiper']",  # 任何包含swiper的元素
        "[class*='slider']",  # 任何包含slider的元素
    ]
    
    swiper_container = None
    
    for selector in swiper_selectors:
        try:
            containers = driver.find_elements(By.CSS_SELECTOR, selector)
            print(f"      -> 选择器 '{selector}' 找到 {len(containers)} 个容器")
            
            for i, container in enumerate(containers):
                try:
                    is_displayed = container.is_displayed()
                    container_size = container.size
                    print(f"        容器 {i+1}: 显示={is_displayed}, 尺寸={container_size}")
                    
                    if is_displayed and container_size['width'] > 0 and container_size['height'] > 0:
                        swiper_container = container
                        print(f"      -> ✓ 选择swiper容器: {selector} [第{i+1}个]")
                        break
                except Exception as e:
                    print(f"        容器检查失败: {e}")
                    continue
            
            if swiper_container:
                break
                
        except Exception as e:
            print(f"      -> 选择器 '{selector}' 执行失败: {e}")
            continue
    
    # 如果找到swiper容器，提取其中的图片
    if swiper_container:
        print(f"      -> ✓ 找到swiper容器，开始提取图片...")
        swiper_images = extract_images_from_swiper(driver, swiper_container)
        all_dialog_images.extend(swiper_images)
        print(f"      -> 从swiper容器提取到 {len(swiper_images)} 个图片")
    else:
        print(f"      -> ❌ 未找到swiper容器")
    
    # 方法2：直接在整个页面查找dialog中的图片（备用方案）
    print(f"      -> 尝试备用方案：直接查找页面中的图片...")
    
    # 查找所有可能是dialog中的图片
    dialog_img_selectors = [
        "img[src*='ci.xiaohongshu.com']",  # 小红书CDN图片
        "img[src*='sns-webpic']",  # 小红书图片服务
        "img[src*='spectrum']",  # 小红书图片处理服务
        "img[class*='image']",  # 包含image class的图片
        "img[class*='photo']",  # 包含photo class的图片
        "img[class*='pic']",  # 包含pic class的图片
        "img",  # 所有图片作为最后备选
    ]
    
    backup_images = []
    for selector in dialog_img_selectors:
        try:
            imgs = driver.find_elements(By.CSS_SELECTOR, selector)
            print(f"      -> 图片选择器 '{selector}' 找到 {len(imgs)} 个图片")
            
            for img in imgs:
                try:
                    if img.is_displayed():
                        img_src = img.get_attribute('src') or img.get_attribute('data-src')
                        if img_src and img_src.startswith('http'):
                            # 过滤明显的小图标和头像
                            img_size = img.size
                            if img_size['width'] > 100 and img_size['height'] > 100:
                                backup_images.append({
                                    'url': img_src,
                                    'element': img,
                                    'width': img_size['width'],
                                    'height': img_size['height'],
                                    'selector': selector
                                })
                                print(f"        -> 备用图片: {img_src[:60]}... 尺寸={img_size}")
                except Exception as e:
                    continue
        except Exception as e:
            print(f"      -> 图片选择器 '{selector}' 执行失败: {e}")
            continue
    
    # 合并所有图片，去重
    if not all_dialog_images and backup_images:
        print(f"      -> 使用备用方案：从 {len(backup_images)} 个备用图片中选择前5个")
        all_dialog_images = backup_images[:5]  # 只取前5个避免下载过多
    
    if not all_dialog_images:
        print(f"      -> ❌ dialog中未找到任何可下载的图片")
        return []
    
    print(f"      -> ✓ 总共找到 {len(all_dialog_images)} 个可下载的图片")
    
    # 下载图片
    downloaded_files = download_dialog_images_enhanced(all_dialog_images, user_title, url_index, total_urls)
    
    return downloaded_files


def download_dialog_images_enhanced(image_elements, user_title, url_index, total_urls):
    """
    增强版dialog图片下载功能
    
    Args:
        image_elements: 图片元素信息列表
        user_title: 用户标题
        url_index: URL索引
        total_urls: 总URL数量
        
    Returns:
        list: 下载的文件路径列表
    """
    
    import requests
    import os
    from urllib.parse import urlparse
    
    print(f"      -> 开始下载 {len(image_elements)} 个图片...")
    
    # 创建下载目录
    download_dir = os.path.join("../output", "images", f"dialog_{user_title}_url{url_index}of{total_urls}")
    if not os.path.exists(download_dir):
        os.makedirs(download_dir)
        print(f"        -> 创建下载目录: {download_dir}")
    
    downloaded_files = []
    
    for i, img_info in enumerate(image_elements):
        try:
            # 获取图片URL
            if isinstance(img_info, dict):
                img_url = img_info.get('url')
                selector_info = img_info.get('selector', 'unknown')
            else:
                img_url = img_info
                selector_info = 'legacy'
            
            if not img_url or not img_url.startswith('http'):
                print(f"        -> 跳过无效URL: {img_url}")
                continue
                
            print(f"        -> 下载第 {i + 1}/{len(image_elements)} 个图片...")
            print(f"           URL: {img_url[:80]}...")
            print(f"           来源: {selector_info}")
            
            # 解析文件名
            parsed_url = urlparse(img_url)
            file_name = os.path.basename(parsed_url.path) or f"dialog_image_{i + 1}.jpg"
            
            # 确保文件名有扩展名
            if '.' not in file_name:
                file_name += '.jpg'
            
            # 构建完整的文件路径
            file_path = os.path.join(download_dir, file_name)
            
            # 下载图片
            headers = {
                'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
                'Referer': 'https://www.xiaohongshu.com/',
                'Accept': 'image/webp,image/apng,image/*,*/*;q=0.8'
            }
            
            response = requests.get(img_url, headers=headers, timeout=30)
            response.raise_for_status()
            
            # 保存文件
            with open(file_path, 'wb') as f:
                f.write(response.content)
            
            file_size = len(response.content)
            downloaded_files.append(file_path)
            print(f"           ✓ 下载成功: {file_name} ({file_size} bytes)")
            
            # 短暂延迟避免请求过于频繁
            sleep(0.5)
            
        except Exception as e:
            print(f"           ❌ 下载失败: {e}")
            continue
    
    print(f"        -> ✓ Dialog图片下载完成，成功下载 {len(downloaded_files)} 个文件")
    
    if downloaded_files:
        print(f"        -> 下载目录: {download_dir}")
        print(f"        -> 文件列表: {[os.path.basename(f) for f in downloaded_files]}")
    
    return downloaded_files
    """
    从swiper容器中提取所有图片元素
    
    Args:
        driver: WebDriver实例
        swiper_container: swiper容器元素
        
    Returns:
        list: 图片元素列表
    """
    
    image_elements = []
    
    # 多种图片选择策略
    image_selectors = [
        "img",  # 直接的img标签
        ".swiper-slide img",  # swiper幻灯片中的图片
        ".swiper-wrapper img",  # swiper包装器中的图片
        "[style*='background-image']",  # 背景图片
        "div[class*='image']",  # 包含image类的div
        "[data-src]",  # 懒加载图片
    ]
    
    for selector in image_selectors:
        try:
            elements = swiper_container.find_elements(By.CSS_SELECTOR, selector)
            
            for element in elements:
                try:
                    if element.is_displayed():
                        # 获取图片URL
                        img_url = None
                        
                        # 方法1: img标签的src属性
                        if element.tag_name == 'img':
                            img_url = element.get_attribute('src') or element.get_attribute('data-src')
                        
                        # 方法2: 背景图片
                        elif 'background-image' in element.get_attribute('style') or '':
                            style = element.get_attribute('style')
                            import re
                            bg_match = re.search(r'background-image:\s*url\(["\']?(.*?)["\']?\)', style)
                            if bg_match:
                                img_url = bg_match.group(1)
                        
                        # 方法3: data-src懒加载
                        else:
                            img_url = element.get_attribute('data-src')
                        
                        if img_url and img_url.startswith('http'):
                            image_elements.append({
                                'element': element,
                                'url': img_url,
                                'selector': selector
                            })
                            print(f"        -> 找到图片: {img_url[:60]}...")
                            
                except Exception as e:
                    continue
                    
        except Exception as e:
            continue
    
    # 去重（基于URL）
    unique_images = []
    seen_urls = set()
    
    for img_info in image_elements:
        if img_info['url'] not in seen_urls:
            seen_urls.add(img_info['url'])
            unique_images.append(img_info)
    
    print(f"        -> 去重后剩余 {len(unique_images)} 个唯一图片")
    return unique_images


def download_swiper_images(driver, image_elements, user_title, url_index, total_urls):
    """
    下载swiper中的图片
    
    Args:
        driver: WebDriver实例
        image_elements: 图片元素信息列表
        user_title: 用户标题
        url_index: URL索引
        total_urls: 总URL数量
        
    Returns:
        list: 下载的文件路径列表
    """
    
    import requests
    import os
    from urllib.parse import urlparse
    
    # 创建下载目录
    download_dir = os.path.join("../output", "images", f"{user_title}_url{url_index}of{total_urls}")
    if not os.path.exists(download_dir):
        os.makedirs(download_dir)
        print(f"        -> 创建下载目录: {download_dir}")
    
    downloaded_files = []
    
    for i, img_info in enumerate(image_elements):
        try:
            img_url = img_info['url']
            print(f"        -> 下载第 {i + 1}/{len(image_elements)} 个图片...")
            print(f"           URL: {img_url}")
            
            # 解析文件名
            parsed_url = urlparse(img_url)
            file_name = os.path.basename(parsed_url.path) or f"image_{i + 1}.jpg"
            
            # 确保文件名有扩展名
            if '.' not in file_name:
                file_name += '.jpg'
            
            # 构建完整的文件路径
            file_path = os.path.join(download_dir, file_name)
            
            # 下载图片
            headers = {
                'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
                'Referer': 'https://www.xiaohongshu.com/'
            }
            
            response = requests.get(img_url, headers=headers, timeout=30)
            response.raise_for_status()
            
            # 保存文件
            with open(file_path, 'wb') as f:
                f.write(response.content)
            
            downloaded_files.append(file_path)
            print(f"           ✓ 下载成功: {file_name}")
            
            # 短暂延迟避免请求过于频繁
            sleep(0.5)
            
        except Exception as e:
            print(f"           ❌ 下载失败: {e}")
            continue
    
    print(f"        -> 图片下载完成，成功下载 {len(downloaded_files)} 个文件")
    return downloaded_files


def check_for_dialog_or_overlay(driver, user_title="unknown", url_index=1, total_urls=1):
    """
    检查是否有dialog或overlay出现，提取URL并下载其中的图片
    
    Args:
        driver: WebDriver实例
        user_title: 用户标题
        url_index: URL索引
        total_urls: 总URL数量
        
    Returns:
        dict: 包含URL和下载的图片信息
    """
    
    print(f"      -> 开始检测dialog...")
    
    # 扩展的dialog选择器，包括小红书特有的选择器和通用检测策略
    dialog_selectors = [
        # 通用dialog选择器
        "[role='dialog']",
        "[role='alertdialog']", 
        ".modal",
        ".overlay",
        ".popup",
        "[class*='dialog']",
        "[class*='modal']",
        "[class*='overlay']",
        "[class*='popup']",
        
        # 小红书特有的选择器
        ".note-detail-mask",  # 笔记详情遮罩
        ".note-detail-popup", # 笔记详情弹窗
        "[class*='note-detail']",  # 包含note-detail的class
        "[class*='detail-modal']", # 详情模态框
        ".fullscreen-modal",  # 全屏模态框
        "[class*='fullscreen']",  # 包含fullscreen的class
        "[class*='viewer']",  # 查看器相关
        "[class*='lightbox']",  # 灯箱效果
        
        # 更通用的弹窗检测
        "div[style*='position: fixed']",  # 固定定位的div
        "div[style*='z-index']",  # 带有层级的div
        "div[style*='position: absolute']",  # 绝对定位的div
        
        # swiper相关的容器也可能作为dialog出现
        "[class*='swiper']",
        "[class*='slider']",
        
        # 基于常见的弹窗特征
        "div[class][style]:not([style=''])",  # 有class和style的div
    ]
    
    dialog_found = False
    current_url = None
    downloaded_images = []
    
    # 首先检查URL是否变化（可能是SPA路由变化）
    current_url = driver.current_url
    if '/explore/' in current_url:
        print(f"      -> ✓ 检测到URL包含explore: {current_url}")
        dialog_found = True  # 标记为找到了内容
    
    # 详细调试信息 - 记录当前页面状态
    print(f"      -> 当前页面URL: {current_url}")
    print(f"      -> 页面标题: {driver.title}")
    
    try:
        window_handles = len(driver.window_handles)
        print(f"      -> 当前窗口数量: {window_handles}")
        
        # 检查页面源码长度作为内容变化的指标
        page_source_length = len(driver.page_source) if driver.page_source else 0
        print(f"      -> 页面内容长度: {page_source_length}")
        
    except Exception as e:
        print(f"      -> 获取页面状态信息失败: {e}")
    
    # 尝试查找dialog元素 - 使用更全面的检测策略
    for i, selector in enumerate(dialog_selectors):
        try:
            dialogs = driver.find_elements(By.CSS_SELECTOR, selector)
            print(f"      -> 选择器 {i+1}/{len(dialog_selectors)} '{selector}': 找到 {len(dialogs)} 个元素")
            
            for j, dialog in enumerate(dialogs):
                try:
                    is_displayed = dialog.is_displayed()
                    element_size = dialog.size
                    element_location = dialog.location
                    element_tag = dialog.tag_name
                    element_class = dialog.get_attribute('class') or ''
                    element_style = dialog.get_attribute('style') or ''
                    
                    print(f"        元素 {j+1}: 显示={is_displayed}, 尺寸={element_size}, 位置={element_location}")
                    print(f"        标签: {element_tag}, class: {element_class[:50]}...")
                    print(f"        style: {element_style[:100]}...")
                    
                    # 更宽松的可见性检查
                    is_likely_dialog = (
                        is_displayed or  # 显示状态
                        (element_size['width'] > 200 and element_size['height'] > 200) or  # 尺寸足够大
                        'position: fixed' in element_style or  # 固定定位
                        'z-index' in element_style  # 有层级
                    )
                    
                    if is_likely_dialog:
                        print(f"        -> ✓ 可能的dialog: {selector} [第{j+1}个元素]")
                        dialog_found = True
                        
                        # 检查是否包含图片元素
                        image_elements = dialog.find_elements(By.TAG_NAME, "img")
                        swiper_elements = dialog.find_elements(By.CSS_SELECTOR, "[class*='swiper']")
                        
                        print(f"        -> dialog中图片数量: {len(image_elements)}")
                        print(f"        -> dialog中swiper数量: {len(swiper_elements)}")
                        
                        if image_elements or swiper_elements:
                            print(f"        -> ✓ 检测到图片内容，该元素可能是dialog")
                            break  # 找到有图片的dialog就停止
                        
                except Exception as e:
                    print(f"        元素检查出错: {e}")
                    continue
                    
            if dialog_found and dialogs:
                break
                
        except Exception as e:
            print(f"      -> 选择器 '{selector}' 执行出错: {e}")
            continue
    
    if dialog_found:
        print(f"      -> ✓ 确认找到dialog或内容变化")
        
        # 等待内容完全加载
        sleep(3)
        
        # 从dialog中下载图片
        print(f"      -> 开始从dialog中下载图片...")
        downloaded_images = download_images_from_dialog(driver, user_title, url_index, total_urls)
        
        if downloaded_images:
            print(f"      -> ✓ 成功下载 {len(downloaded_images)} 个图片")
        else:
            print(f"      -> - dialog中未找到可下载的图片")
        
        # 更新当前URL
        current_url = driver.current_url
        
        return {
            'url': current_url,
            'downloaded_images': downloaded_images,
            'image_count': len(downloaded_images)
        }
    else:
        print(f"      -> 未找到dialog")
        
        # 输出调试信息
        try:
            page_source_preview = driver.page_source[:500] if driver.page_source else "无页面源码"
            print(f"      -> 页面源码前500字符: {page_source_preview}")
            
            # 检查页面中是否有任何swiper相关元素
            swiper_elements = driver.find_elements(By.CSS_SELECTOR, "[class*='swiper']")
            print(f"      -> 页面中swiper相关元素数量: {len(swiper_elements)}")
            
        except Exception as e:
            print(f"      -> 获取调试信息失败: {e}")
        
    return None


def close_dialog_or_overlay(driver):
    """
    关闭dialog或overlay
    
    Args:
        driver: WebDriver实例
    """
    
    # 常见的关闭按钮选择器
    close_selectors = [
        "[aria-label*='关闭']",
        "[aria-label*='close']",
        ".close",
        "[class*='close']",
        "[role='button'][aria-label*='关闭']",
        "button[type='button']"  # 通用按钮
    ]
    
    for selector in close_selectors:
        try:
            close_buttons = driver.find_elements(By.CSS_SELECTOR, selector)
            
            for button in close_buttons:
                if button.is_displayed() and button.is_enabled():
                    button.click()
                    sleep(1)
                    return True
                    
        except Exception as e:
            continue
    
    # 如果找不到关闭按钮，尝试按ESC键
    try:
        ActionChains(driver).send_keys(Keys.ESCAPE).perform()
        sleep(1)
        return True
    except:
        pass
    
    return False


def perform_scroll_operation(driver, attempt_number):
    """执行滚动操作"""
    try:
        # 增加滚动计数并检查是否需要休息
        increment_scroll_count()

        # 获取当前页面高度
        before_height = driver.execute_script("return document.body.scrollHeight")

        # 执行向下滚动
        driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
        sleep(2)

        # 检查是否有高度变化
        after_height = driver.execute_script("return document.body.scrollHeight")

        if after_height > before_height:
            print(f"    页面高度从 {before_height}px 增加到 {after_height}px")
            # 额外等待确保内容完全加载
            sleep(3)
            return True
        else:
            print(f"    页面高度未变化 ({before_height}px)")
            return False

    except Exception as e:
        print(f"    滚动操作失败: {e}")
        return False


def extract_user_title_from_page(driver):
    """
    从页面中提取用户名标题
    """
    try:
        # 尝试多种选择器来查找用户名元素
        selectors = [
            "div.user-name[data-v-1d90bc98]",  # 完整匹配
            "div.user-name",  # 只匹配class
            "div[class*='user-name']",  # 包含user-name class
            ".user-name",  # 简化选择器
            "//div[contains(@class, 'user-name')]",  # XPath选择器
        ]

        for selector in selectors:
            try:
                if selector.startswith("//"):
                    elements = driver.find_elements(By.XPATH, selector)
                else:
                    elements = driver.find_elements(By.CSS_SELECTOR, selector)

                for element in elements:
                    if element.is_displayed():
                        title_text = element.text.strip()
                        if title_text:
                            print(f"  -> 找到用户标题: '{title_text}' (选择器: {selector})")
                            # 清理标题文本，移除文件名中不允许的字符
                            cleaned_title = clean_filename_text(title_text)
                            return cleaned_title
            except Exception as e:
                continue

        print("  -> 未找到用户标题元素")
        return "unknown_user"

    except Exception as e:
        print(f"  -> 提取用户标题时出错: {e}")
        return "unknown_user"


def clean_filename_text(text):
    """
    清理文本以适合作为文件名的一部分
    """
    import re
    # 移除或替换文件名中不允许的字符
    cleaned = re.sub(r'[<>:"/\\|?*]', '_', text)
    # 移除多余的空格和特殊字符
    cleaned = re.sub(r'\s+', '_', cleaned)
    # 限制长度
    cleaned = cleaned[:50] if len(cleaned) > 50 else cleaned
    # 移除开头和结尾的下划线
    cleaned = cleaned.strip('_')
    return cleaned if cleaned else "unknown_user"


def check_xiaohongshu_login_status(driver):
    """
    检测小红书登录状态
    """
    print("正在检测小红书登录状态...")

    # 登录按钮选择器
    login_button_selectors = [
        "button#login-btn",  # ID选择器
        "//button[@id='login-btn']",  # XPath ID选择器
        "button.reds-button-new.login-btn",  # class组合选择器
        "//button[contains(@class, 'reds-button-new') and contains(@class, 'login-btn')]"  # XPath class选择器
    ]

    need_login = False
    found_login_button = None
    login_button_info = {}

    for selector in login_button_selectors:
        try:
            if selector.startswith("//"):
                elements = driver.find_elements(By.XPATH, selector)
            else:
                elements = driver.find_elements(By.CSS_SELECTOR, selector)

            for element in elements:
                if element.is_displayed():
                    need_login = True
                    found_login_button = element
                    login_button_info = {
                        'selector': selector,
                        'id': element.get_attribute('id'),
                        'class': element.get_attribute('class'),
                        'text': element.text.strip(),
                        'is_enabled': element.is_enabled()
                    }
                    print(f"  -> 找到登录按钮: {selector}")
                    break

            if found_login_button:
                break

        except Exception as e:
            continue

    result = {
        'need_login': need_login,
        'found_login_button': found_login_button is not None,
        'login_button_info': login_button_info,
        'page_title': driver.title,
        'current_url': driver.current_url,
        'timestamp': datetime.now().isoformat()
    }

    status_text = "需要登录" if need_login else "已登录"
    print(f"  -> 登录状态检测结果: {status_text}")

    return result


def handle_xiaohongshu_login(driver):
    """
    处理小红书登录流程
    """
    # 登录按钮选择器
    login_button_selectors = [
        "button#login-btn",  # ID选择器
        "//button[@id='login-btn']",  # XPath ID选择器
        "button.reds-button-new.login-btn",  # class组合选择器
        "//button[contains(@class, 'reds-button-new') and contains(@class, 'login-btn')]"  # XPath class选择器
    ]

    print("正在尝试找到并点击登录按钮...")

    for i, selector in enumerate(login_button_selectors):
        try:
            print(f"  -> 尝试选择器 {i + 1}/{len(login_button_selectors)}: {selector}")

            if selector.startswith("//"):
                elements = WebDriverWait(driver, 3).until(
                    EC.presence_of_all_elements_located((By.XPATH, selector))
                )
            else:
                elements = WebDriverWait(driver, 3).until(
                    EC.presence_of_all_elements_located((By.CSS_SELECTOR, selector))
                )

            # 找到可见且可点击的元素
            for element in elements:
                if element.is_displayed() and element.is_enabled():
                    print(f"  -> 找到登录按钮!")

                    # 滚动到元素可见位置
                    driver.execute_script("arguments[0].scrollIntoView({block: 'center'});", element)
                    sleep(1)

                    # 点击登录按钮
                    success = click_login_button(driver, element, selector)
                    if success:
                        return True

        except Exception as e:
            print(f"  -> 选择器 {selector} 未找到元素: {e}")
            continue

    print("  -> 未能找到登录按钮")
    return False


def wait_for_login_completion(driver, max_wait_time=300):
    """
    等待登录完成
    """
    print("正在等待登录完成...")
    print("请在浏览器中扫码登录，程序将自动检测登录状态...")

    # 二维码元素的选择器
    qrcode_selectors = [
        "div.qrcode.force-light",  # class选择器
        ".qrcode",  # 简化class选择器
        "//div[contains(@class, 'qrcode')]",  # XPath选择器
    ]

    # 登录按钮消失选择器
    login_button_selectors = [
        "button#login-btn",
        "//button[@id='login-btn']",
        "button.reds-button-new.login-btn",
    ]

    start_time = time()
    check_interval = 3  # 每3秒检查一次

    while time() - start_time < max_wait_time:
        try:
            # 检查二维码是否仍然存在
            qrcode_exists = False
            for selector in qrcode_selectors:
                try:
                    if selector.startswith("//"):
                        elements = driver.find_elements(By.XPATH, selector)
                    else:
                        elements = driver.find_elements(By.CSS_SELECTOR, selector)

                    for element in elements:
                        if element.is_displayed():
                            qrcode_exists = True
                            break

                    if qrcode_exists:
                        break

                except Exception as e:
                    continue

            # 检查登录按钮是否仍然存在
            login_button_exists = False
            for selector in login_button_selectors:
                try:
                    if selector.startswith("//"):
                        elements = driver.find_elements(By.XPATH, selector)
                    else:
                        elements = driver.find_elements(By.CSS_SELECTOR, selector)

                    for element in elements:
                        if element.is_displayed():
                            login_button_exists = True
                            break

                    if login_button_exists:
                        break

                except Exception as e:
                    continue

            # 如果二维码和登录按钮都消失了，说明登录成功
            if not qrcode_exists and not login_button_exists:
                print("✓ 检测到二维码和登录按钮都已消失，登录成功！")
                sleep(2)  # 等待页面完全加载
                return True

            # 显示等待状态
            elapsed_time = int(time() - start_time)
            remaining_time = max_wait_time - elapsed_time

            if qrcode_exists:
                print(f"  -> 检测到二维码仍存在，继续等待... (已等待 {elapsed_time}s，剩余 {remaining_time}s)")
            elif login_button_exists:
                print(f"  -> 检测到登录按钮仍存在，继续等待... (已等待 {elapsed_time}s，剩余 {remaining_time}s)")

            sleep(check_interval)

        except Exception as e:
            print(f"  -> 检测登录状态时出错: {e}")
            sleep(check_interval)
            continue

    print(f"✗ 登录等待超时 ({max_wait_time}s)，请检查登录状态")
    return False


def download_visible_images_forced(driver, image_elements, user_title, url_index, total_urls):
    """
    强制下载页面中可见的图片元素（不依赖dialog检测）
    
    Args:
        driver: WebDriver实例
        image_elements: 图片元素列表
        user_title: 用户标题
        url_index: URL索引
        total_urls: 总URL数量
        
    Returns:
        list: 下载的文件路径列表
    """
    
    import requests
    import os
    from urllib.parse import urlparse
    
    print(f"      -> 开始强制下载图片...")
    
    # 创建下载目录
    download_dir = os.path.join("../output", "images", f"{user_title}_url{url_index}of{total_urls}_forced")
    if not os.path.exists(download_dir):
        os.makedirs(download_dir)
        print(f"        -> 创建下载目录: {download_dir}")
    
    downloaded_files = []
    
    for i, img_element in enumerate(image_elements):
        try:
            # 获取图片URL
            img_url = img_element.get_attribute('src') or img_element.get_attribute('data-src')
            
            if not img_url or not img_url.startswith('http'):
                print(f"        -> 跳过无效图片URL: {img_url}")
                continue
                
            print(f"        -> 下载强制图片 {i + 1}/{len(image_elements)}...")
            print(f"           URL: {img_url}")
            
            # 解析文件名
            parsed_url = urlparse(img_url)
            file_name = os.path.basename(parsed_url.path) or f"forced_image_{i + 1}.jpg"
            
            # 确保文件名有扩展名
            if '.' not in file_name:
                file_name += '.jpg'
            
            # 构建完整的文件路径
            file_path = os.path.join(download_dir, file_name)
            
            # 下载图片
            headers = {
                'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
                'Referer': 'https://www.xiaohongshu.com/'
            }
            
            response = requests.get(img_url, headers=headers, timeout=30)
            response.raise_for_status()
            
            # 保存文件
            with open(file_path, 'wb') as f:
                f.write(response.content)
            
            downloaded_files.append(file_path)
            print(f"           ✓ 强制下载成功: {file_name}")
            
            # 短暂延迟避免请求过于频繁
            sleep(0.5)
            
        except Exception as e:
            print(f"           ❌ 强制下载失败: {e}")
            continue
    
    print(f"        -> 强制下载完成，成功下载 {len(downloaded_files)} 个文件")
    return downloaded_files



    """
    点击登录按钮的通用方法
    """
    try:
        # 方法1: 直接点击
        element.click()
        print(f"     登录按钮点击成功！(选择器: {selector})")
        sleep(2)
        return True

    except Exception as click_error:
        try:
            # 方法2: JavaScript点击
            driver.execute_script("arguments[0].click();", element)
            print(f"     JavaScript点击成功！(选择器: {selector})")
            sleep(2)
            return True

        except Exception as js_error:
            try:
                # 方法3: ActionChains点击
                ActionChains(driver).move_to_element(element).click().perform()
                print(f"     ActionChains点击成功！(选择器: {selector})")
                sleep(2)
                return True

            except Exception as action_error:
                return False


def save_single_url_result_click_images(url_result, url_index, total_urls):
    """
    保存单个URL的处理结果到重定向JSON文件和拼接字符串文件
    增强版本：确保每个URL都有文件记录，即使没有内容
    """
    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")

    # 提取用户标题和URL
    user_title = url_result.get('user_title', 'unknown_user')
    redirected_urls = url_result.get('redirected_urls', [])
    downloaded_images = url_result.get('downloaded_images', [])
    original_url = url_result.get('url', 'unknown_url')

    # 创建输出目录
    output_dir = "../output"
    if not os.path.exists(output_dir):
        os.makedirs(output_dir)
        print(f"  -> 创建输出目录: {output_dir}")

    # 构建文件名（包含索引信息）
    base_filename = f"xiaohongshu_urls_click_{user_title}_url{url_index}of{total_urls}_{timestamp}"
    redirected_filename = f"{base_filename}_redirected.json"
    concat_filename = f"{base_filename}_urls.txt"

    redirected_filepath = os.path.join(output_dir, redirected_filename)
    concat_filepath = os.path.join(output_dir, concat_filename)

    print(f"  -> 正在保存第 {url_index}/{total_urls} 个URL的结果...")
    print(f"     源URL: {original_url}")
    print(f"     用户: {user_title}")
    print(f"     重定向URL数量: {len(redirected_urls)}")
    print(f"     下载图片数量: {len(downloaded_images)}")
    print(f"     点击链接数量: {url_result.get('total_images_clicked', 0)}")
    print(f"     处理状态: {url_result.get('status', 'unknown')}")

    # 始终保存JSON文件，无论是否有内容
    try:
        redirected_data = {
            "source_url": original_url,
            "user_title": user_title,
            "extraction_timestamp": timestamp,
            "url_index": f"{url_index}/{total_urls}",
            "extraction_method": "click_images_enhanced",
            "total_images_clicked": url_result.get('total_images_clicked', 0),
            "redirected_count": len(redirected_urls),
            "downloaded_images_count": len(downloaded_images),
            "redirected_urls": redirected_urls,
            "downloaded_images": [os.path.basename(img_path) if isinstance(img_path, str) else str(img_path) for img_path in downloaded_images],
            "processing_status": url_result.get('status', 'unknown'),
            "processing_errors": url_result.get('error', None),
            "page_title": url_result.get('page_title', 'unknown'),
            "has_content": len(redirected_urls) > 0 or len(downloaded_images) > 0
        }

        with open(redirected_filepath, 'w', encoding='utf-8') as f:
            json.dump(redirected_data, f, ensure_ascii=False, indent=2)
        print(f"     ✓ JSON文件保存成功: {redirected_filename}")
        
    except Exception as e:
        print(f"     ❌ JSON文件保存失败: {e}")
        redirected_filepath = None

    # 增加重定向文件计数，检查是否需要休息
    increment_redirect_count()

    # 生成URL拼接字符串文件（只有当有重定向URL时）
    try:
        if redirected_urls:
            url_concat_string = ' '.join(redirected_urls)

            with open(concat_filepath, 'w', encoding='utf-8') as f:
                f.write(url_concat_string)
            print(f"     ✓ URL拼接字符串文件: {concat_filename}")
            print(f"     ✓ 拼接字符串长度: {len(url_concat_string)} 字符")
        else:
            concat_filepath = None
            print(f"     - 无重定向URL，跳过拼接字符串文件生成")
            
    except Exception as e:
        print(f"     ❌ TXT文件保存失败: {e}")
        concat_filepath = None

    # 返回文件路径和统计信息
    return redirected_filepath, concat_filepath, len(redirected_urls)


if __name__ == '__main__':
    # 小红书URL列表示例
    url_list = [
        "https://www.xiaohongshu.com/user/profile/659020990000000022001e7f?xsec_token=ABApcqlQBCC4-tZo_YILb7d7K6a0yCAeOIubZfAPMsg8w=&xsec_source=pc_feed",
        # 可以添加更多URL
    ]

    print("=== 小红书URL批量处理工具 (点击图片版本) ===")
    print(f"准备处理 {len(url_list)} 个URL")
    print("本工具将:")
    print("1. 检测登录状态")
    print("2. 如需登录会提示手动扫码")
    print("3. 登录完成后批量处理URL列表")
    print("4. 滚动页面收集图片链接元素")
    print("5. 点击图片链接获取重定向URL")
    print("6. 自动检测并下载dialog中的swiper图片")
    print("7. 自动检测二维码验证并等待用户扫码")
    print("8. 为每个URL生成重定向URL的JSON文件")
    print("9. 为每个URL生成URL拼接字符串的TXT文件")
    print()
    print("=== 防封号机制 ===")
    print(f"- 每处理 {REST_THRESHOLD} 个重定向文件后自动休息 {REST_DURATION // 60} 分钟")
    print(f"- 每滚动 {SCROLL_REST_THRESHOLD} 次后自动休息 {REST_DURATION // 60} 分钟")
    print("- 每点击3个图片后短暂休息，避免被检测为机器人行为")
    print("- 下载图片时每个文件间隔0.5秒")
    print("- 休息期间会显示倒计时提示")
    print()
    print("=== 二维码验证机制 ===")
    print("- 自动检测\"为了保护账号安全，请打开\"等验证文本")
    print("- 检测到验证时会暂停处理并提示用户扫码")
    print("- 验证完成后自动继续处理")
    print("- 最大等待时间：5分钟")
    print()
    print("=== 图片下载机制 ===")
    print("- 自动检测dialog中的swiper容器")
    print("- 下载swiper中的所有图片文件")
    print("- 图片保存到 ../output/images/ 目录")
    print("- 支持多种图片格式和懒加载")
    print()

    # 开始处理
    print("开始处理URL列表...")
    results, driver = process_xiaohongshu_urls_click_images(url_list)

    try:
        print(f"\n=== 处理完成摘要 ===")
        successful_count = len([r for r in results.get('processed_urls', []) if r['status'] == 'success'])
        failed_count = len([r for r in results.get('processed_urls', []) if r['status'] == 'error'])

        print(f"成功处理: {successful_count} 个URL")
        print(f"处理失败: {failed_count} 个URL")
        print(f"每个成功处理的URL都已生成:")
        print(f"  - 重定向URL的JSON文件")
        print(f"  - URL拼接字符串的TXT文件")
        print(f"文件保存位置: ../output/ 目录")

        if results['errors']:
            print(f"\n错误详情:")
            for i, error in enumerate(results['errors'], 1):
                print(f"  {i}. {error}")

    finally:
        # 关闭浏览器
        print("\n处理完成，浏览器将在1秒后关闭...")
        sleep(1)
        driver.quit()

    print("\n=== 最终处理结果摘要 ===")
    print(f"总URL数量: {results['total_urls']}")
    print(f"需要登录: {'是' if results['login_required'] else '否'}")
    print(f"登录完成: {'是' if results['login_completed'] else '否'}")
    print(f"成功处理: {len([r for r in results['processed_urls'] if r['status'] == 'success'])}")
    print(f"处理失败: {len([r for r in results['processed_urls'] if r['status'] == 'error'])}")
    print(f"错误数量: {len(results['errors'])}")

    print("\n处理完成！每个URL都已生成JSON和TXT文件。")